#coding=utf-8
'''
 树莓派总函数
 负责：
   模块启动时，各部分正常工作的检查
   调取gps数据，并且发送到前端
   收集扫码数据
'''
import threading
import time
import cv2
import serial
import pynmea2
import requests
import json
import inspect
import ctypes
import logging
import sys


# 自己写的包
import gps
import check
import config
import Qrcode


'''
gps的启动线程类
'''
class gps_thread(threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name

    def run(self):
        logging.debug("[main.py] gps线程开启：" + self.name)
        print ("[main.py] gps线程开启：" + self.name)
        gps.gps_send()
        logging.debug("[main.py] gps线程主动结束：" + self.name)
        print ("[main.py] gps线程主动结束：" + self.name)


'''
二维码启动的线程类
'''
class qrcode_thread(threading.Thread):
    def __init__(self, threadID, name):
        threading.Thread.__init__(self)
        self.threadID = threadID
        self.name = name

    def run(self):
        print ("[main.py] qrcode线程开启：" + self.name)
        logging.debug("[main.py] qrcode线程开启：" + self.name)
        Qrcode.scan_code()
        print ("[main.py] qrcode线程主动结束：" + self.name)
        logging.debug("[main.py] qrcode线程主动结束：" + self.name)


def _async_raise(tid, exctype):
    """raises the exception, performs cleanup if needed"""
    tid = ctypes.c_long(tid)
    if not inspect.isclass(exctype):
        exctype = type(exctype)
    res = ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, ctypes.py_object(exctype))
    if res == 0:
        raise ValueError("invalid thread id")
    elif res != 1:
        # """if it returns a number greater than one, you're in trouble,
        # and you should call it again with exc=NULL to revert the effect"""
        ctypes.pythonapi.PyThreadState_SetAsyncExc(tid, None)
        raise SystemError("PyThreadState_SetAsyncExc failed")


def stop_thread(thread):
    _async_raise(thread.ident, SystemExit)




'''
主函数
'''
def raspberry_main():
    # 开机后，进程休眠40秒，待传感器稳定
    #time.sleep(30)

    # 车辆自检
    localtime = time.asctime( time.localtime(time.time()) )
    print(localtime, "[raspberry_main]: 车辆启动，开始自检 " )
    logging.debug("[raspberry_main]: 车辆启动，开始自检 ")
    ret_status = check.check_bus()
    if ret_status == 1:
        print(localtime, "[raspberry_main]: 车辆自检成功" )
        logging.debug("[raspberry_main]: 车辆自检成功")
    else:
        print(localtime, "[raspberry_main]:车辆自检失败，请重启树莓派" )
        logging.error("[raspberry_main]:车辆自检失败，请重启树莓派")

        print('[raspberry_main]: 主线程任务结束')
        logging.debug('[raspberry_main]: 主线程任务结束')
        return

    # 自检完毕
    if ret_status == 1:
        config.BUS_STATUS = -1
        # 启动扫码进程，等待司机扫码（此段时间拒绝用户扫码）
        qrcodeThread = qrcode_thread(1, 'qrcode_thread')
        qrcodeThread.start()

        # 司机扫码结束，树莓派完成身份注册（与车牌号绑定），此时开启gps线程，向后台传递‘有身份’的GPS数据
        gpsThread = gps_thread(2, 'gps_thread')
        gpsThread.start()


    '''
    线程关闭判断
    当树莓派向服务器查询，当这一段车辆任务已经执行完毕，则树莓派就可以自动停止所有进程了(作废)
    当人为按下关机键，就可以关机了
    '''
    while True:
        if (cv2.waitKey(1)) == ord('q'):
            break
        time.sleep(2)
    
    config.GPS_STOP = 1  # 停止两个线程的循环
    config.QRCODE_STOP = 1

    time.sleep(4)

    if qrcodeThread.is_alive():
        config.cap.release()
        cv2.destroyAllWindows() 
        stop_thread(qrcodeThread)
        print('[raspberry_main]: qrcode线程强制结束')
        logging.debug('[raspberry_main]: qrcode线程强制结束')

    if gpsThread.is_alive():
        stop_thread(gpsThread)
        print('[raspberry_main]: gps线程强制结束')
        logging.debug('[raspberry_main]: gps线程强制结束')

    print('[raspberry_main]: 主线程任务结束')
    logging.debug('[raspberry_main]: 主线程任务结束')
    return



if __name__ == '__main__':

        # 开启日志
    logging.basicConfig(filename=config.LOG_FILENAME, level=logging.DEBUG, format=config.LOG_FORMAT)
    logging.debug('\n\n***********开启日志**********\n ')

    if len(sys.argv) >= 2 and sys.argv[1]=='0':  # 正式版
        config.TEST = '0'
        config.URL = config.URL_REAL # 使用正式url
        logging.debug('Program Start! Using nomal version')
    else:
        config.TEST = '1'  # 测试版
        #config.URL = config.URL_REAL # 使用正式url
        print(config.URL)
        print('Using test version')
        logging.debug('Program Start! Using test version')

    
    raspberry_main()


    








        
        
    